import authCache from "@/uni-sdk/utils/authCache.js";
import {
	getCodeMessage
} from "./code-message.js";
import {
	ResultCodeEnum,
	HttpStatusEnum,
	RequestMethodEnum,
	ContentTypeEnum
} from "./enum.js";
import {
	isEmptyObj,
	isObj
} from "@/uni-sdk/utils/common.js";

const DEFAULT_ERR_MESSAGE = "加载失败，请稍候再试";
const AuthenticationScheme = "Bearer";

function dealErrorResponse(response) {
	if (response) {
		if (response.data) {
			const codeMsg = getCodeMessage(response.data.code);
			if (codeMsg) {
				response.data.msg = codeMsg;
			}
		}
	}
	return (
		response.data || {
			code: response.statusCode,
			msg: response.statusText,
		}
	);
}

function showToast(msg) {
	getApp().globalData.toast(msg, true);
}

function toLogin(loginParams) {
	uni.reLaunch({
		url: "/pages/login/login" + (loginParams ? ("?" + loginParams) : ""),
	});
}

export function getAuthHeader(isAutoRedirect, loginParams) {
	const token = authCache.getToken();
	if (token) {
		return {
			Authorization: `${AuthenticationScheme} ${token}`,
		};
	} else {
		if (isAutoRedirect) {
			showToast("请先登录");
			toLogin(loginParams);
		}
		return null;
	}
}
/**
 * 对uni.request的二次封装
 * @param {Object} config uni.request的config对象 (https://uniapp.dcloud.io/api/request/request.html#request)
 * @param {Object} options 自定义额外配置选项
 * @property {Boolean} useDefaultFailHandle 默认的请求失败处理
 * @property {Boolean} useDefaultErrHandle 默认的请求错误处理
 * @property {Boolean} withToken 是否带token
 * @property {Boolean} useGlobalLoading 是否有uni.showLoading的全局加载效果
 * @property {Boolean} autoPrefixBaseUrl 是否自动加上common.baseUrl的域名
 * @property {String} loginParams 当验证token失败时跳转到登录页的附加参数字符串
 */
function doReq(config, options) {
	options = Object.assign({
		useDefaultFailHandle: true,
		useDefaultErrHandle: true,
		withToken: true,
		useGlobalLoading: false,
		autoPrefixBaseUrl: true,
		loginParams: "",
		contentTypeKey: "JSON",
	}, options || {});
	if (!config.header) {
		config.header = {};
	}
	config.header["Content-Type"] = ContentTypeEnum[options.contentTypeKey];
	if (options.withToken) {
		const authHeader = getAuthHeader(true, options.loginParams);
		if (authHeader) {
			Object.assign(config.header, authHeader);
		} else {
			return Promise.reject(null);
		}
	}
	if (options.useGlobalLoading) {
		uni.showLoading({
			title: "加载中...",
			mask: true,
		});
	}
	if (options.autoPrefixBaseUrl) {
		config.url = getApp().globalData.common.baseUrl + config.url;
	}
	config.timeout = 10000;
	return new Promise((resolve, reject) => {
		config.fail = (response) => {
			console.log("请求失败", config.url, config.data, response);
			const data = response ?
				dealErrorResponse(response) : {
					msg: null,
					code: null,
				};
			if (options.useDefaultErrHandle) {
				//默认异常处理
				showToast(data.msg || DEFAULT_ERR_MESSAGE);
				resolve(null);
				if (data.code === ResultCodeEnum.JWT_NOT_LOGIN ||
					data.code === ResultCodeEnum.JWT_TOKEN_EXPIRED) {
					toLogin(options.loginParams);
				}
			} else {
				//自定义异常处理
				reject(data);
			}
		};
		config.success = (response) => {
			console.log("请求成功", config.url, config.data, response);
			if (response.statusCode === HttpStatusEnum.SUCCESS) {
				const data = response.data;
				if (data) {
					if (data.code === ResultCodeEnum.SUCCESS || data.code === ResultCodeEnum.SUCCESS200) {
						resolve(data.data ? data.data : {
							_isEmptyOrNull: true
						});
					} else if (data.code === ResultCodeEnum.UNAUTHORIZED || data.code === ResultCodeEnum
						.JWT_NOT_LOGIN) {
						//token过期或未登录
						toLogin(options.loginParams);
						resolve(null);
						if (data.code === ResultCodeEnum.JWT_NOT_LOGIN) {
							showToast(getCodeMessage(ResultCodeEnum.JWT_NOT_LOGIN));
						}
					} else {
						const codeMsg = getCodeMessage(data.code);
						if (codeMsg) {
							data.msg = codeMsg;
						}
						if (options.useDefaultFailHandle) {
							showToast(data.msg || DEFAULT_ERR_MESSAGE);
							resolve(null);
						} else {
							reject(data);
						}
					}
					return;
				}
			}
			const errLogs = [];
			console.log("================>error info begin");
			errLogs.push(config.url);
			errLogs.push(config.data ? JSON.stringify(config.data) : "{}");
			response.data && response.data.errorMsg && errLogs.push(response.data.errorMsg);
			console.log(errLogs.join("\n"));
			console.log("================>error info end");
			if (options.useDefaultErrHandle) {
				if(response.statusCode === HttpStatusEnum.UNAUTHORIZED) {
					showToast("请先登录");
					toLogin(options.loginParams);
				} else {
					showToast(DEFAULT_ERR_MESSAGE);
					resolve(null);
				}
			} else {
				reject({
					code: response.statusCode,
					msg: response.statusText,
				});
			}
		};
		config.complete = () => {
			if (options.useGlobalLoading) {
				uni.hideLoading();
			}
		};
		uni.request(config);
	});
}

function handleCommonReq(url, method, dataOrLoading, loadingOrOptions) {
	let data;
	if (typeof dataOrLoading === 'boolean') {
		loadingOrOptions = dataOrLoading;
		data = {};
	} else {
		data = dataOrLoading;
	}
	const config = {
		url,
		method,
		data
	};
	let options = {};
	if (typeof loadingOrOptions === 'boolean') {
		options.useGlobalLoading = loadingOrOptions;
	} else {
		options = loadingOrOptions;
	}
	return doReq(config, options);
}
const req = {
	get(config, options) {
		config.method = RequestMethodEnum.GET;
		return doReq(config, options);
	},
	getPage(config, options) {
		config.method = RequestMethodEnum.POST;
		config.data = Object.assign({
			current: 1,
			size: 10,
		}, config.data);
		return doReq(config, options);
	},
	post(config, options) {
		config.method = RequestMethodEnum.POST;
		return doReq(config, options);
	},
	delete(config, options) {
		config.method = RequestMethodEnum.DELETE;
		return doReq(config, options);
	},
	put(config, options) {
		config.method = RequestMethodEnum.PUT;
		return doReq(config, options);
	},
	commonGet(url, dataOrLoading, loadingOrOptions = true) {
		return handleCommonReq(url, RequestMethodEnum.GET, dataOrLoading, loadingOrOptions);
	},
	commonPost(url, dataOrLoading, loadingOrOptions = true) {
		return handleCommonReq(url, RequestMethodEnum.POST, dataOrLoading, loadingOrOptions);
	}
};
export default req;